package luaj.utils.functions;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import luaj.LuaError;
import luaj.LuaTables;
import luaj.LuaValue;
import luaj.Varargs;
import luaj.lib.LibFunction;
import luaj.lib.OneArgFunction;
import luaj.lib.TwoArgFunction;
import luaj.lib.jse.CoerceLuaToJava;
import luaj.lib.jse.LuajavaLib;

/**
 * Created by nirenr on 2020/1/16.
 */
public class JsonLib extends TwoArgFunction {




    public static String encode(LuaValue value) {
        Object map = toJson(value);
        return map.toString();
    }
    
    private static Object toJson(LuaValue value) {
        LuaTables t = (LuaTables) value.checktable();
        if(t.length()==t.size()){
            JSONArray arr = new JSONArray();
            for (int i = 0; i < t.length(); i++) {
                LuaValue v = t.get(i + 1);
                if(v.istable())
                    arr.put(toJson(v));
                else
                    arr.put(CoerceLuaToJava.coerce(v, Object.class));
            }
            return arr;
        }
        JSONObject map = new JSONObject();
        Varargs ret = value.next(LuaValue.NIL);
        while (ret != LuaValue.NIL) {
            LuaValue k = ret.arg1();
            LuaValue v = ret.arg(2);
            try {
                if (v.istable())
                    map.put(k.tojstring(), toJson(v));
                else
                    map.put(k.tojstring(), CoerceLuaToJava.coerce(v, Object.class));
            } catch (JSONException e) {

                e.printStackTrace();
            }
            ret = value.next(k);
        }
        return map;
    }

    public static LuaValue decode(String text){
        try {
            if(text.startsWith("["))
                return LuajavaLib.asTable(new JSONArray(text));
            return LuajavaLib.asTable(new JSONObject(text));
        } catch (Exception e) {

            e.printStackTrace();
            throw new LuaError(e.getMessage());
        }
        //return NIL;
    }

    public LuaValue call(LuaValue modname, LuaValue env) {
        LuaTables json = new LuaTables();
        json.set("decode", new decode());
        json.set("encode", new encode());
        env.set("json", json);
        if (!env.get("package").isnil()) env.get("package").get("loaded").set("json", json);
        return NIL;
    }

    private class decode extends OneArgFunction {
        @Override
        public LuaValue call(LuaValue arg) {
            return decode(arg.tojstring());
        }
    }

    private class encode extends OneArgFunction {
        @Override
        public LuaValue call(LuaValue arg) {
            return LuaValue.valueOf(encode(arg));
        }
    }

}
